package com.gadgets.framework.statusmach.util;

import com.gadgets.framework.common.constant.GadgetsConstant;
import com.gadgets.framework.common.util.CacheUtils;
import com.gadgets.framework.common.util.SpringUtils;
import com.gadgets.framework.statusmach.dto.StatusMachineQueryDTO;
import com.gadgets.framework.statusmach.exception.GadgetsStatusMachineException;
import com.gadgets.framework.statusmach.pojo.StatusMachine;
import com.gadgets.framework.statusmach.repository.IStatusMachineRepository;
import org.springframework.util.StringUtils;

import java.util.HashMap;
import java.util.List;

/**
 * @author UncleXiu
 * @version V1.0.0
 * @data 2020-09-27
 * 
 */
public class StatusUtil {

    protected static HashMap<String,HashMap<String, StatusMachine>> STATUS_MACHINE_CACHE_MAP = new HashMap<>();

    protected static CacheUtils cacheUtils = null;

    private static IStatusMachineRepository repository = null;

    /**
     * 将状态机加入到本地缓存Map当中
     * @param machine   状态机对象
     */
    public static void addStatusMachine(StatusMachine machine){
        if(!STATUS_MACHINE_CACHE_MAP.containsKey(machine.getMachineCode())){
            STATUS_MACHINE_CACHE_MAP.put(machine.getMachineCode(), new HashMap<>());
        }
        if(StringUtils.isEmpty(machine.getMachineParam())){
            STATUS_MACHINE_CACHE_MAP.get(machine.getMachineCode()).put(GadgetsConstant.NUMBER_CONSTANT.STR_CHARAT_Z, machine);
        }else {
            STATUS_MACHINE_CACHE_MAP.get(machine.getMachineCode()).put(machine.getMachineParam(), machine);
        }
    }

    /**
     * 将状态机刷进缓存
     */
    public static void refreshStatusCache(){
        if(null==cacheUtils){
            cacheUtils = SpringUtils.getBeanByName("cacheUtils",CacheUtils.class);
        }
        if(null==repository){
            repository = SpringUtils.getBeanByName("IStatusMachineRepository",IStatusMachineRepository.class);
        }
        cacheUtils.putDefualtCache("machineStatus",STATUS_MACHINE_CACHE_MAP);
    }

    /**
     * 获取指定码值的状态机
     * @param machineCode   状态机ID码
     * @param machineParam  状态机分支参数
     */
    @SuppressWarnings("unchecked")
    public static StatusMachine getStatusMachine(String machineCode, String machineParam){
        if(null==cacheUtils){
            cacheUtils = SpringUtils.getBeanByName("cacheUtils",CacheUtils.class);
        }
        if(null==repository){
            repository = SpringUtils.getBeanByName("IStatusMachineRepository",IStatusMachineRepository.class);
        }
        if(StringUtils.isEmpty(machineParam)){
            machineParam = GadgetsConstant.NUMBER_CONSTANT.STR_CHARAT_Z;
        }
        StatusMachineQueryDTO queryDTO = new StatusMachineQueryDTO();
        queryDTO.setMachineCode(machineCode);
        STATUS_MACHINE_CACHE_MAP = cacheUtils.getDefaultCache("machineStatus",HashMap.class);
        if(STATUS_MACHINE_CACHE_MAP.containsKey(machineCode)){
            cacheDBQuery(queryDTO);
            return STATUS_MACHINE_CACHE_MAP.get(machineCode).getOrDefault(machineParam, null);
        }else {
            StatusMachine target = null;
            // 如果缓存中没有命中当前状态机ID码，则去数据库查询一下
            cacheDBQuery(queryDTO);
            return STATUS_MACHINE_CACHE_MAP.get(machineCode).getOrDefault(machineParam, null);
        }
    }

    /**
     * 当缓存未命中状态机时，通过数据库刷新缓存
     * @param queryDTO  查询条件
     */
    protected static void cacheDBQuery(StatusMachineQueryDTO queryDTO) {
        // 如果缓存中没有命中当前状态机ID码，则去数据库查询一下
        List<StatusMachine> machines = repository.queryStatusMachine(queryDTO);
        for (StatusMachine machine : machines) {
            addStatusMachine(machine);
            refreshStatusCache();
        }
    }

    /**
     * 以字符串数组的形式获取状态机前置状态
     * @param machineCode       状态机ID码
     * @param machineParam      状态机分支参数
     * @return                  前置状态数组
     */
    public static String[] getBeforeStatus(String machineCode, String machineParam){
        StatusMachine machine = getStatusMachine(machineCode, machineParam);
        if(null==machine){
            throw new GadgetsStatusMachineException(machineCode, machineParam);
        }
        String beforeStatus = machine.getBeforeStatus();
        if(!StringUtils.isEmpty(beforeStatus)){
            return beforeStatus.split(",");
        }
        throw new GadgetsStatusMachineException(machineCode, machineParam);
    }

    /**
     * 以整形数组的形式获取状态机前置状态
     * @param machineCode       状态机ID码
     * @param machineParam      状态机分支参数
     * @return                  前置状态数组
     */
    public static Integer[] getBeforeStatusByInt(String machineCode, String machineParam){
        String[] status = getBeforeStatus(machineCode, machineParam);
        Integer[] ret = new Integer[status.length];
        for (int i = 0; i < status.length; i++) {
            ret[i] = Integer.parseInt(status[i]);
        }
        return ret;
    }

}
